package com.zwps.biz.domain.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zwps.biz.api.model.vo.ststbprp.StStbprpBVO;
import com.zwps.biz.dal.db.dao.ForecastWeatherDAO;
import com.zwps.biz.dal.db.object.ForecastWeatherDO;
import com.zwps.biz.domain.service.FloodWeatherScrapService;
import com.zwps.biz.domain.service.StStbprpBService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class FloodWeatherScrapServiceImpl implements FloodWeatherScrapService {

    @Autowired
    private StStbprpBService stStbprpBService;

    @Autowired
    private ForecastWeatherDAO forecastWeatherDAO;

    @Value(value = "${FloodWeather.apikey}")
    private String apikey;

    @Override
    public void floodWeatherScrap() {
        List<StStbprpBVO> stStbprpBVOList = stStbprpBService.getStcdBySttp("pp");

        for (StStbprpBVO stStbprpBVO : stStbprpBVOList) {
            String apiResponse = fetchWeatherData(stStbprpBVO.getLgtd().doubleValue(), stStbprpBVO.getLttd().doubleValue(), apikey);
            if (apiResponse != null) {
                // 解析JSON数据
                WeatherData weatherData = parseWeatherData(apiResponse);
                if (weatherData != null && CollectionUtil.isNotEmpty(weatherData.getHourDataList())) {
                    // 保存数据
                    saveWeatherData(weatherData.getHourDataList(), stStbprpBVO.getStcd());
                }
            }
        }
    }

    @Transactional
    private void saveWeatherData(List<HourData> hourDataList, String stcd) {
        List<ForecastWeatherDO> weatherDOList = hourDataList.stream()
                .map(item -> new ForecastWeatherDO(item.getTime(), item.getRainAmount(), item.getHumidity(), item.getTemperature(), stcd))
                .collect(Collectors.toList());

        List<String> times = weatherDOList.stream().map(ForecastWeatherDO::getTime).collect(Collectors.toList());

        forecastWeatherDAO.deleteByTimeAndStcd(times, stcd);

        if (CollectionUtil.isNotEmpty(weatherDOList)) {
            forecastWeatherDAO.batchInsert(weatherDOList);
        }
    }
    
    // JSON解析器
    private static final ObjectMapper objectMapper = new ObjectMapper();
    
    // 解析天气数据JSON
    private static WeatherData parseWeatherData(String jsonResponse) {
        try {
            WeatherData weatherData = new WeatherData();

            // 解析JSON
            JsonNode rootNode = objectMapper.readTree(jsonResponse);

            // 导航到小时数据
            JsonNode responsesNode = rootNode.path("responses");
            if (responsesNode.isArray() && !responsesNode.isEmpty()) {
                JsonNode weatherNode = responsesNode.get(0).path("weather");
                if (weatherNode.isArray() && !weatherNode.isEmpty()) {
                    JsonNode forecastNode = weatherNode.get(0).path("forecast");
                    JsonNode daysNode = forecastNode.path("days");

                    if (daysNode.isArray()) {
                        // 遍历每天的数据
                        for (JsonNode dayNode : daysNode) {
                            JsonNode hourlyNode = dayNode.path("hourly");

                            if (hourlyNode.isArray()) {
                                // 遍历每小时的数据
                                for (JsonNode hourNode : hourlyNode) {
                                    String time = convertIsoDate(hourNode.path("valid").asText());
                                    double rainAmount = hourNode.path("rainAmount").asDouble();
                                    int humidity = hourNode.path("rh").asInt();
                                    double temperature = hourNode.path("temp").asDouble();

                                    weatherData.addHourData(new HourData(time, rainAmount, humidity, temperature));
                                }
                            }
                        }
                    }
                }
            }

            return weatherData;
        } catch (Exception e) {
            log.error("解析天气数据失败: " + e.getMessage());
            e.printStackTrace();
            return null;
        }
    }

    public static String convertIsoDate(String isoDate) {
        OffsetDateTime offsetDateTime = OffsetDateTime.parse(isoDate);
        LocalDateTime localDateTime = offsetDateTime.toLocalDateTime();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        return localDateTime.format(formatter);
    }

    private static String fetchWeatherData(double lonitude, double latitude, String apiKey) {
        String url = String.format("https://api.msn.cn/weather/overview?apikey=%s&ocid=msftweather&cm=zh-cn&it=edgeid&units=c&appId=9e21380c-ff19-4c78-b4ea-19558e93a5d3&wrapodata=false&includemapsmetadata=true&cuthour=true&lifeDays=2&lifeModes=18&includestorm=true&includeLifeActivity=true&lifeSubTypes=1%%2C3%%4%%2C10%%2C26&days=10&source=weather_csr&hours=240&fdhead=prg-1sw-wxbgsmrc%%2Cprg-1sw-wxmptreplace%%2Cprg-1sw-wxrvlocds%%2Cprg-1sw-wxinsightvc%%2Cprg-1sw-wxtrgaprev&region=cn&market=zh-cn&locale=zh-cn&lat=%s&lon=%s",
                apiKey, latitude, lonitude);

        int attempts = 5;
        int backoffTime = 10; // 初始等待时间（秒）

        while (attempts > 0) {
            try {
                URL obj = new URL(url);
                HttpURLConnection con = (HttpURLConnection) obj.openConnection();

                // 设置请求头
                con.setRequestMethod("GET");
                con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.0.0");

                // 获取响应
                int responseCode = con.getResponseCode();
                if (responseCode == HttpURLConnection.HTTP_OK) {
                    try (BufferedReader in = new BufferedReader(
                            new InputStreamReader(con.getInputStream(), StandardCharsets.UTF_8))) {

                        StringBuilder response = new StringBuilder();
                        String inputLine;
                        while ((inputLine = in.readLine()) != null) {
                            response.append(inputLine);
                        }

                        return response.toString();
                    }
                } else {
                    log.error("HTTP请求失败，状态码: " + responseCode);
                }
            } catch (Exception e) {
                log.error("尝试重新连接，剩余尝试次数：" + (attempts - 1) + "，错误：" + e.getMessage());
            }

            // 指数退避
            try {
                Thread.sleep(backoffTime * 1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }

            backoffTime *= 2;
            attempts--;
        }

        log.error("所有重试失败，无法获取数据");
        return null;
    }

    // 天气数据类
    static class WeatherData {
        private final List<HourData> hourDataList = new ArrayList<>();

        public void addHourData(HourData hourData) {
            hourDataList.add(hourData);
        }

        public List<HourData> getHourDataList() {
            return hourDataList;
        }
    }

    // 小时数据类
    @Data
    static class HourData {
        private final String time;
        private final double rainAmount;
        private final int humidity;
        private final double temperature;

        public HourData(String time, double rainAmount, int humidity, double temperature) {
            this.time = time;
            this.rainAmount = rainAmount;
            this.humidity = humidity;
            this.temperature = temperature;
        }
    }
}
